/**
 * TinyMCE version 7.7.1 (2025-03-05)
 */

(function() {
  "use strict";

  var global$5 = tinymce.util.Tools.resolve("tinymce.PluginManager");

  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = x => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType = type => value => typeOf(value) === type;
  const isSimpleType = type => value => typeof value === type;
  const eq = t => a => t === a;
  const isString = isType("string");
  const isObject = isType("object");
  const isArray = isType("array");
  const isNull = eq(null);
  const isBoolean = isSimpleType("boolean");
  const isNullable = a => a === null || a === undefined;
  const isNonNullable = a => !isNullable(a);
  const isFunction = isSimpleType("function");
  const isArrayOf = (value, pred) => {
    if (isArray(value)) {
      for (let i = 0, len = value.length; i < len; ++i) {
        if (!pred(value[i])) {
          return false;
        }
      }
      return true;
    }
    return false;
  };

  const noop = () => {
  };
  const constant = value => {
    return () => {
      return value;
    };
  };
  const tripleEquals = (a, b) => {
    return a === b;
  };

  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }

    static some(value) {
      return new Optional(true, value);
    }

    static none() {
      return Optional.singletonNone;
    }

    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }

    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }

    isSome() {
      return this.tag;
    }

    isNone() {
      return !this.tag;
    }

    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }

    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }

    exists(predicate) {
      return this.tag && predicate(this.value);
    }

    forall(predicate) {
      return !this.tag || predicate(this.value);
    }

    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }

    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }

    or(replacement) {
      return this.tag ? this : replacement;
    }

    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }

    orThunk(thunk) {
      return this.tag ? this : thunk();
    }

    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }

    getOrNull() {
      return this.tag ? this.value : null;
    }

    getOrUndefined() {
      return this.value;
    }

    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }

    toArray() {
      return this.tag ? [this.value] : [];
    }

    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }

  Optional.singletonNone = new Optional(false);

  const nativeIndexOf = Array.prototype.indexOf;
  const nativePush = Array.prototype.push;
  const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  const contains = (xs, x) => rawIndexOf(xs, x) > -1;
  const map = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const foldl = (xs, f, acc) => {
    each$1(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const flatten = xs => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };
  const bind = (xs, f) => flatten(map(xs, f));
  const findMap = (arr, f) => {
    for (let i = 0; i < arr.length; i++) {
      const r = f(arr[i], i);
      if (r.isSome()) {
        return r;
      }
    }
    return Optional.none();
  };

  const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
  const cat = arr => {
    const r = [];
    const push = x => {
      r.push(x);
    };
    for (let i = 0; i < arr.length; i++) {
      arr[i].each(push);
    }
    return r;
  };
  const someIf = (b, a) => b ? Optional.some(a) : Optional.none();

  const option = name => editor => editor.options.get(name);
  const register$1 = editor => {
    const registerOption = editor.options.register;
    registerOption("link_assume_external_targets", {
      processor: value => {
        const valid = isString(value) || isBoolean(value);
        if (valid) {
          if (value === true) {
            return {
              value: 1,
              valid
            };
          } else if (value === "http" || value === "https") {
            return {
              value,
              valid
            };
          } else {
            return {
              value: 0,
              valid
            };
          }
        } else {
          return {
            valid: false,
            message: "Must be a string or a boolean."
          };
        }
      },
      default: false
    });
    registerOption("link_context_toolbar", {
      processor: "boolean",
      default: false
    });
    registerOption("link_list", { processor: value => isString(value) || isFunction(value) || isArrayOf(value, isObject) });
    registerOption("link_default_target", { processor: "string" });
    registerOption("link_default_protocol", {
      processor: "string",
      default: "https"
    });
    registerOption("link_target_list", {
      processor: value => isBoolean(value) || isArrayOf(value, isObject),
      default: true
    });
    registerOption("link_rel_list", {
      processor: "object[]",
      default: []
    });
    registerOption("link_class_list", {
      processor: "object[]",
      default: []
    });
    registerOption("link_title", {
      processor: "boolean",
      default: true
    });
    registerOption("allow_unsafe_link_target", {
      processor: "boolean",
      default: false
    });
    registerOption("link_quicklink", {
      processor: "boolean",
      default: false
    });
    registerOption("link_attributes_postprocess", { processor: "function" });
  };
  const assumeExternalTargets = option("link_assume_external_targets");
  const hasContextToolbar = option("link_context_toolbar");
  const getLinkList = option("link_list");
  const getDefaultLinkTarget = option("link_default_target");
  const getDefaultLinkProtocol = option("link_default_protocol");
  const getTargetList = option("link_target_list");
  const getRelList = option("link_rel_list");
  const getLinkClassList = option("link_class_list");
  const shouldShowLinkTitle = option("link_title");
  const allowUnsafeLinkTarget = option("allow_unsafe_link_target");
  const useQuickLink = option("link_quicklink");
  const attributesPostProcess = option("link_attributes_postprocess");

  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const objAcc = r => (x, i) => {
    r[i] = x;
  };
  const internalFilter = (obj, pred, onTrue, onFalse) => {
    each(obj, (x, i) => {
      (pred(x, i) ? onTrue : onFalse)(x, i);
    });
  };
  const filter = (obj, pred) => {
    const t = {};
    internalFilter(obj, pred, objAcc(t), noop);
    return t;
  };
  const has = (obj, key) => hasOwnProperty.call(obj, key);
  const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== undefined && obj[key] !== null;

  var global$4 = tinymce.util.Tools.resolve("tinymce.util.URI");

  var global$3 = tinymce.util.Tools.resolve("tinymce.dom.TreeWalker");

  var global$2 = tinymce.util.Tools.resolve("tinymce.util.Tools");

  const isAnchor = elm => isNonNullable(elm) && elm.nodeName.toLowerCase() === "a";
  const isLink = elm => isAnchor(elm) && !!getHref(elm);
  const collectNodesInRange = (rng, predicate) => {
    if (rng.collapsed) {
      return [];
    } else {
      const contents = rng.cloneContents();
      const firstChild = contents.firstChild;
      const walker = new global$3(firstChild, contents);
      const elements = [];
      let current = firstChild;
      do {
        if (predicate(current)) {
          elements.push(current);
        }
      } while (current = walker.next());
      return elements;
    }
  };
  const hasProtocol = url => /^\w+:/i.test(url);
  const getHref = elm => {
    var _a, _b;
    return (_b = (_a = elm.getAttribute("data-mce-href")) !== null && _a !== void 0 ? _a : elm.getAttribute("href")) !== null && _b !== void 0 ? _b : "";
  };
  const applyRelTargetRules = (rel, isUnsafe) => {
    const rules = ["noopener"];
    const rels = rel ? rel.split(/\s+/) : [];
    const toString = rels => global$2.trim(rels.sort().join(" "));
    const addTargetRules = rels => {
      rels = removeTargetRules(rels);
      return rels.length > 0 ? rels.concat(rules) : rules;
    };
    const removeTargetRules = rels => rels.filter(val => global$2.inArray(rules, val) === -1);
    const newRels = isUnsafe ? addTargetRules(rels) : removeTargetRules(rels);
    return newRels.length > 0 ? toString(newRels) : "";
  };
  const trimCaretContainers = text => text.replace(/\uFEFF/g, "");
  const getAnchorElement = (editor, selectedElm) => {
    selectedElm = selectedElm || getLinksInSelection(editor.selection.getRng())[0] || editor.selection.getNode();
    if (isImageFigure(selectedElm)) {
      return Optional.from(editor.dom.select("a[href]", selectedElm)[0]);
    } else {
      return Optional.from(editor.dom.getParent(selectedElm, "a[href]"));
    }
  };
  const isInAnchor = (editor, selectedElm) => getAnchorElement(editor, selectedElm).isSome();
  const getAnchorText = (selection, anchorElm) => {
    const text = anchorElm.fold(() => selection.getContent({ format: "text" }), anchorElm => anchorElm.innerText || anchorElm.textContent || "");
    return trimCaretContainers(text);
  };
  const getLinksInSelection = rng => collectNodesInRange(rng, isLink);
  const getLinks$1 = elements => global$2.grep(elements, isLink);
  const hasLinks = elements => getLinks$1(elements).length > 0;
  const hasLinksInSelection = rng => getLinksInSelection(rng).length > 0;
  const isOnlyTextSelected = editor => {
    const inlineTextElements = editor.schema.getTextInlineElements();
    const isElement = elm => elm.nodeType === 1 && !isAnchor(elm) && !has(inlineTextElements, elm.nodeName.toLowerCase());
    const isInBlockAnchor = getAnchorElement(editor).exists(anchor => anchor.hasAttribute("data-mce-block"));
    if (isInBlockAnchor) {
      return false;
    }
    const rng = editor.selection.getRng();
    if (!rng.collapsed) {
      const elements = collectNodesInRange(rng, isElement);
      return elements.length === 0;
    } else {
      return true;
    }
  };
  const isImageFigure = elm => isNonNullable(elm) && elm.nodeName === "FIGURE" && /\bimage\b/i.test(elm.className);

  const getLinkAttrs = data => {
    const attrs = [
      "title",
      "rel",
      "class",
      "target"
    ];
    return foldl(attrs, (acc, key) => {
      data[key].each(value => {
        acc[key] = value.length > 0 ? value : null;
      });
      return acc;
    }, { href: data.href });
  };
  const handleExternalTargets = (href, assumeExternalTargets) => {
    if ((assumeExternalTargets === "http" || assumeExternalTargets === "https") && !hasProtocol(href)) {
      return assumeExternalTargets + "://" + href;
    }
    return href;
  };
  const applyLinkOverrides = (editor, linkAttrs) => {
    const newLinkAttrs = { ...linkAttrs };
    if (getRelList(editor).length === 0 && !allowUnsafeLinkTarget(editor)) {
      const newRel = applyRelTargetRules(newLinkAttrs.rel, newLinkAttrs.target === "_blank");
      newLinkAttrs.rel = newRel ? newRel : null;
    }
    if (Optional.from(newLinkAttrs.target).isNone() && getTargetList(editor) === false) {
      newLinkAttrs.target = getDefaultLinkTarget(editor);
    }
    newLinkAttrs.href = handleExternalTargets(newLinkAttrs.href, assumeExternalTargets(editor));
    return newLinkAttrs;
  };
  const updateLink = (editor, anchorElm, text, linkAttrs) => {
    text.each(text => {
      if (has(anchorElm, "innerText")) {
        anchorElm.innerText = text;
      } else {
        anchorElm.textContent = text;
      }
    });
    editor.dom.setAttribs(anchorElm, linkAttrs);
    const rng = editor.dom.createRng();
    rng.setStartAfter(anchorElm);
    rng.setEndAfter(anchorElm);
    editor.selection.setRng(rng);
  };
  const createLink = (editor, selectedElm, text, linkAttrs) => {
    const dom = editor.dom;
    if (isImageFigure(selectedElm)) {
      linkImageFigure(dom, selectedElm, linkAttrs);
    } else {
      text.fold(() => {
        editor.execCommand("mceInsertLink", false, linkAttrs);
        const end = editor.selection.getEnd();
        const rng = dom.createRng();
        rng.setStartAfter(end);
        rng.setEndAfter(end);
        editor.selection.setRng(rng);
      }, text => {
        editor.insertContent(dom.createHTML("a", linkAttrs, dom.encode(text)));
      });
    }
  };
  const linkDomMutation = (editor, attachState, data) => {
    const selectedElm = editor.selection.getNode();
    const anchorElm = getAnchorElement(editor, selectedElm);
    const linkAttrs = applyLinkOverrides(editor, getLinkAttrs(data));
    const attributesPostProcess$1 = attributesPostProcess(editor);
    if (isNonNullable(attributesPostProcess$1)) {
      attributesPostProcess$1(linkAttrs);
    }
    editor.undoManager.transact(() => {
      if (data.href === attachState.href) {
        attachState.attach();
      }
      anchorElm.fold(() => {
        createLink(editor, selectedElm, data.text, linkAttrs);
      }, elm => {
        editor.focus();
        updateLink(editor, elm, data.text, linkAttrs);
      });
    });
  };
  const unlinkSelection = editor => {
    const dom = editor.dom, selection = editor.selection;
    const bookmark = selection.getBookmark();
    const rng = selection.getRng().cloneRange();
    const startAnchorElm = dom.getParent(rng.startContainer, "a[href]", editor.getBody());
    const endAnchorElm = dom.getParent(rng.endContainer, "a[href]", editor.getBody());
    if (startAnchorElm) {
      rng.setStartBefore(startAnchorElm);
    }
    if (endAnchorElm) {
      rng.setEndAfter(endAnchorElm);
    }
    selection.setRng(rng);
    editor.execCommand("unlink");
    selection.moveToBookmark(bookmark);
  };
  const unlinkDomMutation = editor => {
    editor.undoManager.transact(() => {
      const node = editor.selection.getNode();
      if (isImageFigure(node)) {
        unlinkImageFigure(editor, node);
      } else {
        unlinkSelection(editor);
      }
      editor.focus();
    });
  };
  const unwrapOptions = data => {
    const {
      class: cls,
      href,
      rel,
      target,
      text,
      title
    } = data;
    return filter({
      class: cls.getOrNull(),
      href,
      rel: rel.getOrNull(),
      target: target.getOrNull(),
      text: text.getOrNull(),
      title: title.getOrNull()
    }, (v, _k) => isNull(v) === false);
  };
  const sanitizeData = (editor, data) => {
    const getOption = editor.options.get;
    const uriOptions = {
      allow_html_data_urls: getOption("allow_html_data_urls"),
      allow_script_urls: getOption("allow_script_urls"),
      allow_svg_data_urls: getOption("allow_svg_data_urls")
    };
    const href = data.href;
    return {
      ...data,
      href: global$4.isDomSafe(href, "a", uriOptions) ? href : ""
    };
  };
  const link = (editor, attachState, data) => {
    const sanitizedData = sanitizeData(editor, data);
    editor.hasPlugin("rtc", true) ? editor.execCommand("createlink", false, unwrapOptions(sanitizedData)) : linkDomMutation(editor, attachState, sanitizedData);
  };
  const unlink = editor => {
    editor.hasPlugin("rtc", true) ? editor.execCommand("unlink") : unlinkDomMutation(editor);
  };
  const unlinkImageFigure = (editor, fig) => {
    var _a;
    const img = editor.dom.select("img", fig)[0];
    if (img) {
      const a = editor.dom.getParents(img, "a[href]", fig)[0];
      if (a) {
        (_a = a.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(img, a);
        editor.dom.remove(a);
      }
    }
  };
  const linkImageFigure = (dom, fig, attrs) => {
    var _a;
    const img = dom.select("img", fig)[0];
    if (img) {
      const a = dom.create("a", attrs);
      (_a = img.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(a, img);
      a.appendChild(img);
    }
  };

  const getValue = item => isString(item.value) ? item.value : "";
  const getText = item => {
    if (isString(item.text)) {
      return item.text;
    } else if (isString(item.title)) {
      return item.title;
    } else {
      return "";
    }
  };
  const sanitizeList = (list, extractValue) => {
    const out = [];
    global$2.each(list, item => {
      const text = getText(item);
      if (item.menu !== undefined) {
        const items = sanitizeList(item.menu, extractValue);
        out.push({
          text,
          items
        });
      } else {
        const value = extractValue(item);
        out.push({
          text,
          value
        });
      }
    });
    return out;
  };
  const sanitizeWith = (extracter = getValue) => list => Optional.from(list).map(list => sanitizeList(list, extracter));
  const sanitize = list => sanitizeWith(getValue)(list);
  const createUi = (name, label) => items => ({
    name,
    type: "listbox",
    label,
    items
  });
  const ListOptions = {
    sanitize,
    sanitizeWith,
    createUi,
    getValue
  };

  const isListGroup = item => hasNonNullableKey(item, "items");
  const findTextByValue = (value, catalog) => findMap(catalog, item => {
    if (isListGroup(item)) {
      return findTextByValue(value, item.items);
    } else {
      return someIf(item.value === value, item);
    }
  });
  const getDelta = (persistentText, fieldName, catalog, data) => {
    const value = data[fieldName];
    const hasPersistentText = persistentText.length > 0;
    return value !== undefined ? findTextByValue(value, catalog).map(i => ({
      url: {
        value: i.value,
        meta: {
          text: hasPersistentText ? persistentText : i.text,
          attach: noop
        }
      },
      text: hasPersistentText ? persistentText : i.text
    })) : Optional.none();
  };
  const findCatalog = (catalogs, fieldName) => {
    if (fieldName === "link") {
      return catalogs.link;
    } else if (fieldName === "anchor") {
      return catalogs.anchor;
    } else {
      return Optional.none();
    }
  };
  const init = (initialData, linkCatalog) => {
    const persistentData = {
      text: initialData.text,
      title: initialData.title
    };
    const getTitleFromUrlChange = url => {
      var _a;
      return someIf(persistentData.title.length <= 0, Optional.from((_a = url.meta) === null || _a === void 0 ? void 0 : _a.title).getOr(""));
    };
    const getTextFromUrlChange = url => {
      var _a;
      return someIf(persistentData.text.length <= 0, Optional.from((_a = url.meta) === null || _a === void 0 ? void 0 : _a.text).getOr(url.value));
    };
    const onUrlChange = data => {
      const text = getTextFromUrlChange(data.url);
      const title = getTitleFromUrlChange(data.url);
      if (text.isSome() || title.isSome()) {
        return Optional.some({
          ...text.map(text => ({ text })).getOr({}),
          ...title.map(title => ({ title })).getOr({})
        });
      } else {
        return Optional.none();
      }
    };
    const onCatalogChange = (data, change) => {
      const catalog = findCatalog(linkCatalog, change).getOr([]);
      return getDelta(persistentData.text, change, catalog, data);
    };
    const onChange = (getData, change) => {
      const name = change.name;
      if (name === "url") {
        return onUrlChange(getData());
      } else if (contains([
        "anchor",
        "link"
      ], name)) {
        return onCatalogChange(getData(), name);
      } else if (name === "text" || name === "title") {
        persistentData[name] = getData()[name];
        return Optional.none();
      } else {
        return Optional.none();
      }
    };
    return { onChange };
  };
  const DialogChanges = {
    init,
    getDelta
  };

  var global$1 = tinymce.util.Tools.resolve("tinymce.util.Delay");

  const delayedConfirm = (editor, message, callback) => {
    const rng = editor.selection.getRng();
    global$1.setEditorTimeout(editor, () => {
      editor.windowManager.confirm(message, state => {
        editor.selection.setRng(rng);
        callback(state);
      });
    });
  };
  const tryEmailTransform = data => {
    const url = data.href;
    const suggestMailTo = url.indexOf("@") > 0 && url.indexOf("/") === -1 && url.indexOf("mailto:") === -1;
    return suggestMailTo ? Optional.some({
      message: "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",
      preprocess: oldData => ({
        ...oldData,
        href: "mailto:" + url
      })
    }) : Optional.none();
  };
  const tryProtocolTransform = (assumeExternalTargets, defaultLinkProtocol) => data => {
    const url = data.href;
    const suggestProtocol = assumeExternalTargets === 1 && !hasProtocol(url) || assumeExternalTargets === 0 && /^\s*www(\.|\d\.)/i.test(url);
    return suggestProtocol ? Optional.some({
      message: `The URL you entered seems to be an external link. Do you want to add the required ${defaultLinkProtocol}:// prefix?`,
      preprocess: oldData => ({
        ...oldData,
        href: defaultLinkProtocol + "://" + url
      })
    }) : Optional.none();
  };
  const preprocess = (editor, data) => findMap([
    tryEmailTransform,
    tryProtocolTransform(assumeExternalTargets(editor), getDefaultLinkProtocol(editor))
  ], f => f(data)).fold(() => Promise.resolve(data), transform => new Promise(callback => {
    delayedConfirm(editor, transform.message, state => {
      callback(state ? transform.preprocess(data) : data);
    });
  }));
  const DialogConfirms = { preprocess };

  const getAnchors = editor => {
    const anchorNodes = editor.dom.select("a:not([href])");
    const anchors = bind(anchorNodes, anchor => {
      const id = anchor.name || anchor.id;
      return id ? [{
        text: id,
        value: "#" + id
      }] : [];
    });
    return anchors.length > 0 ? Optional.some([{
      text: "None",
      value: ""
    }].concat(anchors)) : Optional.none();
  };
  const AnchorListOptions = { getAnchors };

  const getClasses = editor => {
    const list = getLinkClassList(editor);
    if (list.length > 0) {
      return ListOptions.sanitize(list);
    }
    return Optional.none();
  };
  const ClassListOptions = { getClasses };

  const parseJson = text => {
    try {
      return Optional.some(JSON.parse(text));
    } catch (_a) {
      return Optional.none();
    }
  };
  const getLinks = editor => {
    const extractor = item => editor.convertURL(item.value || item.url || "", "href");
    const linkList = getLinkList(editor);
    return new Promise(resolve => {
      if (isString(linkList)) {
        fetch(linkList).then(res => res.ok ? res.text().then(parseJson) : Promise.reject()).then(resolve, () => resolve(Optional.none()));
      } else if (isFunction(linkList)) {
        linkList(output => resolve(Optional.some(output)));
      } else {
        resolve(Optional.from(linkList));
      }
    }).then(optItems => optItems.bind(ListOptions.sanitizeWith(extractor)).map(items => {
      if (items.length > 0) {
        const noneItem = [{
          text: "None",
          value: ""
        }];
        return noneItem.concat(items);
      } else {
        return items;
      }
    }));
  };
  const LinkListOptions = { getLinks };

  const getRels = (editor, initialTarget) => {
    const list = getRelList(editor);
    if (list.length > 0) {
      const isTargetBlank = is(initialTarget, "_blank");
      const enforceSafe = allowUnsafeLinkTarget(editor) === false;
      const safeRelExtractor = item => applyRelTargetRules(ListOptions.getValue(item), isTargetBlank);
      const sanitizer = enforceSafe ? ListOptions.sanitizeWith(safeRelExtractor) : ListOptions.sanitize;
      return sanitizer(list);
    }
    return Optional.none();
  };
  const RelOptions = { getRels };

  const fallbacks = [
    {
      text: "Current window",
      value: ""
    },
    {
      text: "New window",
      value: "_blank"
    }
  ];
  const getTargets = editor => {
    const list = getTargetList(editor);
    if (isArray(list)) {
      return ListOptions.sanitize(list).orThunk(() => Optional.some(fallbacks));
    } else if (list === false) {
      return Optional.none();
    }
    return Optional.some(fallbacks);
  };
  const TargetOptions = { getTargets };

  const nonEmptyAttr = (dom, elem, name) => {
    const val = dom.getAttrib(elem, name);
    return val !== null && val.length > 0 ? Optional.some(val) : Optional.none();
  };
  const extractFromAnchor = (editor, anchor) => {
    const dom = editor.dom;
    const onlyText = isOnlyTextSelected(editor);
    const text = onlyText ? Optional.some(getAnchorText(editor.selection, anchor)) : Optional.none();
    const url = anchor.bind(anchorElm => Optional.from(dom.getAttrib(anchorElm, "href")));
    const target = anchor.bind(anchorElm => Optional.from(dom.getAttrib(anchorElm, "target")));
    const rel = anchor.bind(anchorElm => nonEmptyAttr(dom, anchorElm, "rel"));
    const linkClass = anchor.bind(anchorElm => nonEmptyAttr(dom, anchorElm, "class"));
    const title = anchor.bind(anchorElm => nonEmptyAttr(dom, anchorElm, "title"));
    return {
      url,
      text,
      title,
      target,
      rel,
      linkClass
    };
  };
  const collect = (editor, linkNode) => LinkListOptions.getLinks(editor).then(links => {
    const anchor = extractFromAnchor(editor, linkNode);
    return {
      anchor,
      catalogs: {
        targets: TargetOptions.getTargets(editor),
        rels: RelOptions.getRels(editor, anchor.target),
        classes: ClassListOptions.getClasses(editor),
        anchor: AnchorListOptions.getAnchors(editor),
        link: links
      },
      optNode: linkNode,
      flags: { titleEnabled: shouldShowLinkTitle(editor) }
    };
  });
  const DialogInfo = { collect };

  const handleSubmit = (editor, info) => api => {
    const data = api.getData();
    if (!data.url.value) {
      unlink(editor);
      api.close();
      return;
    }
    const getChangedValue = key => Optional.from(data[key]).filter(value => !is(info.anchor[key], value));
    const changedData = {
      href: data.url.value,
      text: getChangedValue("text"),
      target: getChangedValue("target"),
      rel: getChangedValue("rel"),
      class: getChangedValue("linkClass"),
      title: getChangedValue("title")
    };
    const attachState = {
      href: data.url.value,
      attach: data.url.meta !== undefined && data.url.meta.attach ? data.url.meta.attach : noop
    };
    DialogConfirms.preprocess(editor, changedData).then(pData => {
      link(editor, attachState, pData);
    });
    api.close();
  };
  const collectData = editor => {
    const anchorNode = getAnchorElement(editor);
    return DialogInfo.collect(editor, anchorNode);
  };
  const getInitialData = (info, defaultTarget) => {
    const anchor = info.anchor;
    const url = anchor.url.getOr("");
    return {
      url: {
        value: url,
        meta: { original: { value: url } }
      },
      text: anchor.text.getOr(""),
      title: anchor.title.getOr(""),
      anchor: url,
      link: url,
      rel: anchor.rel.getOr(""),
      target: anchor.target.or(defaultTarget).getOr(""),
      linkClass: anchor.linkClass.getOr("")
    };
  };
  const makeDialog = (settings, onSubmit, editor) => {
    const urlInput = [{
      name: "url",
      type: "urlinput",
      filetype: "file",
      label: "URL",
      picker_text: "Browse links"
    }];
    const displayText = settings.anchor.text.map(() => ({
      name: "text",
      type: "input",
      label: "Text to display"
    })).toArray();
    const titleText = settings.flags.titleEnabled ? [{
      name: "title",
      type: "input",
      label: "Title"
    }] : [];
    const defaultTarget = Optional.from(getDefaultLinkTarget(editor));
    const initialData = getInitialData(settings, defaultTarget);
    const catalogs = settings.catalogs;
    const dialogDelta = DialogChanges.init(initialData, catalogs);
    const body = {
      type: "panel",
      items: flatten([
        urlInput,
        displayText,
        titleText,
        cat([
          catalogs.anchor.map(ListOptions.createUi("anchor", "Anchors")),
          catalogs.rels.map(ListOptions.createUi("rel", "Rel")),
          catalogs.targets.map(ListOptions.createUi("target", "Open link in...")),
          catalogs.link.map(ListOptions.createUi("link", "Link list")),
          catalogs.classes.map(ListOptions.createUi("linkClass", "Class"))
        ])
      ])
    };
    return {
      title: "Insert/Edit Link",
      size: "normal",
      body,
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      initialData,
      onChange: (api, { name }) => {
        dialogDelta.onChange(api.getData, { name }).each(newData => {
          api.setData(newData);
        });
      },
      onSubmit
    };
  };
  const open = editor => {
    const data = collectData(editor);
    data.then(info => {
      const onSubmit = handleSubmit(editor, info);
      return makeDialog(info, onSubmit, editor);
    }).then(spec => {
      editor.windowManager.open(spec);
    });
  };

  const register = editor => {
    editor.addCommand("mceLink", (_ui, value) => {
      if ((value === null || value === void 0 ? void 0 : value.dialog) === true || !useQuickLink(editor)) {
        open(editor);
      } else {
        editor.dispatch("contexttoolbar-show", { toolbarKey: "quicklink" });
      }
    });
  };

  const setup$2 = editor => {
    editor.addShortcut("Meta+K", "", () => {
      editor.execCommand("mceLink");
    });
  };

  const Cell = initial => {
    let value = initial;
    const get = () => {
      return value;
    };
    const set = v => {
      value = v;
    };
    return {
      get,
      set
    };
  };

  const singleton = doRevoke => {
    const subject = Cell(Optional.none());
    const revoke = () => subject.get().each(doRevoke);
    const clear = () => {
      revoke();
      subject.set(Optional.none());
    };
    const isSet = () => subject.get().isSome();
    const get = () => subject.get();
    const set = s => {
      revoke();
      subject.set(Optional.some(s));
    };
    return {
      clear,
      isSet,
      get,
      set
    };
  };
  const value = () => {
    const subject = singleton(noop);
    const on = f => subject.get().each(f);
    return {
      ...subject,
      on
    };
  };

  const removeFromStart = (str, numChars) => {
    return str.substring(numChars);
  };

  const checkRange = (str, substr, start) => substr === "" || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  const removeLeading = (str, prefix) => {
    return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
  };
  const startsWith = (str, prefix) => {
    return checkRange(str, prefix, 0);
  };

  var global = tinymce.util.Tools.resolve("tinymce.util.VK");

  const appendClickRemove = (link, evt) => {
    document.body.appendChild(link);
    link.dispatchEvent(evt);
    document.body.removeChild(link);
  };
  const openLink = url => {
    const link = document.createElement("a");
    link.target = "_blank";
    link.href = url;
    link.rel = "noreferrer noopener";
    const evt = new MouseEvent("click", {
      bubbles: true,
      cancelable: true,
      view: window
    });
    document.dispatchEvent(evt);
    appendClickRemove(link, evt);
  };
  const hasOnlyAltModifier = e => {
    return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
  };
  const gotoLink = (editor, a) => {
    if (a) {
      const href = getHref(a);
      if (/^#/.test(href)) {
        const targetEl = editor.dom.select(`${href},[name="${removeLeading(href, "#")}"]`);
        if (targetEl.length) {
          editor.selection.scrollIntoView(targetEl[0], true);
        }
      } else {
        openLink(a.href);
      }
    }
  };
  const isSelectionOnImageWithEmbeddedLink = editor => {
    const rng = editor.selection.getRng();
    const node = rng.startContainer;
    return isLink(node) && rng.startContainer === rng.endContainer && editor.dom.select("img", node).length === 1;
  };
  const getLinkFromElement = (editor, element) => {
    const links = getLinks$1(editor.dom.getParents(element));
    return someIf(links.length === 1, links[0]);
  };
  const getLinkInSelection = editor => {
    const links = getLinksInSelection(editor.selection.getRng());
    return someIf(links.length > 0, links[0]).or(getLinkFromElement(editor, editor.selection.getNode()));
  };
  const getLinkFromSelection = editor => editor.selection.isCollapsed() || isSelectionOnImageWithEmbeddedLink(editor) ? getLinkFromElement(editor, editor.selection.getStart()) : getLinkInSelection(editor);
  const setup$1 = editor => {
    const selectedLink = value();
    const getSelectedLink = () => selectedLink.get().or(getLinkFromSelection(editor));
    const gotoSelectedLink = () => getSelectedLink().each(link => gotoLink(editor, link));
    editor.on("contextmenu", e => {
      getLinkFromElement(editor, e.target).each(selectedLink.set);
    });
    editor.on("SelectionChange", () => {
      if (!selectedLink.isSet()) {
        getLinkFromSelection(editor).each(selectedLink.set);
      }
    });
    editor.on("click", e => {
      selectedLink.clear();
      const links = getLinks$1(editor.dom.getParents(e.target));
      if (links.length === 1 && global.metaKeyPressed(e)) {
        e.preventDefault();
        gotoLink(editor, links[0]);
      }
    });
    editor.on("keydown", e => {
      selectedLink.clear();
      if (!e.isDefaultPrevented() && e.keyCode === 13 && hasOnlyAltModifier(e)) {
        getSelectedLink().each(link => {
          e.preventDefault();
          gotoLink(editor, link);
        });
      }
    });
    return { gotoSelectedLink };
  };

  const openDialog = editor => () => {
    editor.execCommand("mceLink", false, { dialog: true });
  };
  const toggleState = (editor, toggler) => {
    editor.on("NodeChange", toggler);
    return () => editor.off("NodeChange", toggler);
  };
  const toggleLinkState = editor => api => {
    const updateState = () => {
      api.setActive(!editor.mode.isReadOnly() && isInAnchor(editor, editor.selection.getNode()));
      api.setEnabled(editor.selection.isEditable());
    };
    updateState();
    return toggleState(editor, updateState);
  };
  const toggleLinkMenuState = editor => api => {
    const updateState = () => {
      api.setEnabled(editor.selection.isEditable());
    };
    updateState();
    return toggleState(editor, updateState);
  };
  const toggleRequiresLinkState = editor => api => {
    const hasLinks$1 = parents => hasLinks(parents) || hasLinksInSelection(editor.selection.getRng());
    const parents = editor.dom.getParents(editor.selection.getStart());
    const updateEnabled = parents => {
      api.setEnabled(hasLinks$1(parents) && editor.selection.isEditable());
    };
    updateEnabled(parents);
    return toggleState(editor, e => updateEnabled(e.parents));
  };
  const setupButtons = (editor, openLink) => {
    editor.ui.registry.addToggleButton("link", {
      icon: "link",
      tooltip: "Insert/edit link",
      shortcut: "Meta+K",
      onAction: openDialog(editor),
      onSetup: toggleLinkState(editor)
    });
    editor.ui.registry.addButton("openlink", {
      icon: "new-tab",
      tooltip: "Open link",
      onAction: openLink.gotoSelectedLink,
      onSetup: toggleRequiresLinkState(editor)
    });
    editor.ui.registry.addButton("unlink", {
      icon: "unlink",
      tooltip: "Remove link",
      onAction: () => unlink(editor),
      onSetup: toggleRequiresLinkState(editor)
    });
  };
  const setupMenuItems = (editor, openLink) => {
    editor.ui.registry.addMenuItem("openlink", {
      text: "Open link",
      icon: "new-tab",
      onAction: openLink.gotoSelectedLink,
      onSetup: toggleRequiresLinkState(editor)
    });
    editor.ui.registry.addMenuItem("link", {
      icon: "link",
      text: "Link...",
      shortcut: "Meta+K",
      onAction: openDialog(editor),
      onSetup: toggleLinkMenuState(editor)
    });
    editor.ui.registry.addMenuItem("unlink", {
      icon: "unlink",
      text: "Remove link",
      onAction: () => unlink(editor),
      onSetup: toggleRequiresLinkState(editor)
    });
  };
  const setupContextMenu = editor => {
    const inLink = "link unlink openlink";
    const noLink = "link";
    editor.ui.registry.addContextMenu("link", {
      update: element => {
        const isEditable = editor.dom.isEditable(element);
        if (!isEditable) {
          return "";
        }
        return hasLinks(editor.dom.getParents(element, "a")) ? inLink : noLink;
      }
    });
  };
  const setupContextToolbars = (editor, openLink) => {
    const collapseSelectionToEnd = editor => {
      editor.selection.collapse(false);
    };
    const onSetupLink = buttonApi => {
      const node = editor.selection.getNode();
      buttonApi.setEnabled(isInAnchor(editor, node) && editor.selection.isEditable());
      return noop;
    };
    const getLinkText = value => {
      const anchor = getAnchorElement(editor);
      const onlyText = isOnlyTextSelected(editor);
      if (anchor.isNone() && onlyText) {
        const text = getAnchorText(editor.selection, anchor);
        return someIf(text.length === 0, value);
      } else {
        return Optional.none();
      }
    };
    editor.ui.registry.addContextForm("quicklink", {
      launch: {
        type: "contextformtogglebutton",
        icon: "link",
        tooltip: "Link",
        onSetup: toggleLinkState(editor)
      },
      label: "Link",
      predicate: node => hasContextToolbar(editor) && isInAnchor(editor, node),
      initValue: () => {
        const elm = getAnchorElement(editor);
        return elm.fold(constant(""), getHref);
      },
      commands: [
        {
          type: "contextformtogglebutton",
          icon: "link",
          tooltip: "Link",
          primary: true,
          onSetup: buttonApi => {
            const node = editor.selection.getNode();
            buttonApi.setActive(isInAnchor(editor, node));
            return toggleLinkState(editor)(buttonApi);
          },
          onAction: formApi => {
            const value = formApi.getValue();
            const text = getLinkText(value);
            const attachState = {
              href: value,
              attach: noop
            };
            link(editor, attachState, {
              href: value,
              text,
              title: Optional.none(),
              rel: Optional.none(),
              target: Optional.from(getDefaultLinkTarget(editor)),
              class: Optional.none()
            });
            collapseSelectionToEnd(editor);
            formApi.hide();
          }
        },
        {
          type: "contextformbutton",
          icon: "unlink",
          tooltip: "Remove link",
          onSetup: onSetupLink,
          onAction: formApi => {
            unlink(editor);
            formApi.hide();
          }
        },
        {
          type: "contextformbutton",
          icon: "new-tab",
          tooltip: "Open link",
          onSetup: onSetupLink,
          onAction: formApi => {
            openLink.gotoSelectedLink();
            formApi.hide();
          }
        }
      ]
    });
  };
  const setup = editor => {
    const openLink = setup$1(editor);
    setupButtons(editor, openLink);
    setupMenuItems(editor, openLink);
    setupContextMenu(editor);
    setupContextToolbars(editor, openLink);
  };

  var Plugin = () => {
    global$5.add("link", editor => {
      register$1(editor);
      register(editor);
      setup(editor);
      setup$2(editor);
    });
  };

  Plugin();

})();
